package main

import "reflect"

///////////////////////////////////////////////////////////////
//////////// Tag Finder

type TagFinder struct {
	name string
	path map[string][]string
}

func NewTagFinder(i interface{}, name string) *TagFinder {
	finder := &TagFinder{}
	finder.name = name
	finder.path = make(map[string][]string)
	finder.init(reflect.ValueOf(i).Elem(), []string{})
	return finder
}

func (this *TagFinder) init(val reflect.Value, way []string) {
	for i := 0; i < val.NumField(); i++ {
		switch val.Field(i).Kind() {
		case reflect.Struct:
			way = append(way, val.Type().Field(i).Name)
			this.init(val.Field(i), way)
			way = way[:len(way)-1]
		default:
			tag := val.Type().Field(i).Tag.Get(this.name)
			if tag != "" {
				way = append(way, val.Type().Field(i).Name)
				way_copy := make([]string, len(way))
				copy(way_copy, way)
				this.path[tag] = way_copy
				way = way[:len(way)-1]
			}
		}
	}
}

func (this *TagFinder) GetValue(i interface{}, name string) *reflect.Value {
	if way, ok := this.path[name]; ok {
		v := reflect.ValueOf(i).Elem()
		for _, w := range way {
			v = v.FieldByName(w)
		}
		return &v
	}
	return nil
}

func (this *TagFinder) GetInt(i interface{}, name string) int {
	return int(this.GetValue(i, name).Int())
}

func (this *TagFinder) GetString(i interface{}, name string) string {
	return this.GetValue(i, name).String()
}
